#ifndef __Path_h_
#define __Path_h_

#include <iostream>
#include <fstream>
#include <ostream>
#include <vector>
#include <map>
#include <iterator>
#include <sstream>
#include <algorithm>
#include <climits>
#include <stdio.h>

#include "tinyxml/tinyxml.h"
#include "tinyxml/tinystr.h"

using namespace std;


class Path
{
   private:

      // key: slice, value: label
      //map< int, long int > p_path;
      //float p_cost;
      vector< int > p_slices ;
      vector< long int > p_labels;
      vector< double > p_costs ;
      vector< double > p_accumulated_costs ;
      vector< int > p_x;
      vector< int > p_y;

      unsigned short p_unique_id;

      vector< string > p_vtk_filenames; 
      // note: there might be more than one vtk file for each full path

      float p_final_cost;

      bool p_init;

      
   public:

      //
      //  empty constructor
      //
      Path( ); 
      //~Path() { };

      //
      //  copy constructor
      // 
      Path( const Path& p ) ;
      Path( const Path* p ) ;

      //
      //  operator=
      //
      Path& operator=( const Path& p ) ;

      //
      // clear - reset the path
      //
      void clear() ;

      //
      //  merge paths that are sequential slices
      //
      void merge( const Path& P ) ;
      bool overlap( const Path* P );
      float combine( const Path* P );

      //
      //  get info just based on the index of the vector
      //
      int getSliceAtIndex( unsigned int i ) { return p_slices[ i ]; };
      int getXAtIndex( unsigned int i ) { return p_x[ i ]; };
      int getYAtIndex( unsigned int i ) { return p_y[ i ]; };
      long int getLabelAtIndex( unsigned int i ) { return p_labels[ i ]; };

      //
      //  merge paths that share a last and first slice
      //
      void merge( const Path& P, bool use_this ) ;

      //
      //  length between slices (not the size of the vector)
      //
      unsigned int length() const;

      //
      //  return the first label in the path
      //
      long int getFirstLabel() ;

      //
      //  return the first slice in the path
      //
      int beginningSlice() const ;
      //
      //  return the last slice in the path
      //
      int lastSlice() const ;

      //
      //  returns the first slice in the path
      //
      int firstSlice() const ;

      //
      //  get a list of all the slices
      //
      vector< int >& getSlices() ;

      //
      //  getCost
      //
      float getCost() const ;

      //
      //  setCost
      //
      void setCost( float cost ) ;

      //
      //  getSlice at index i
      //
      int getSlice( int i ) const ;

      //
      //  getLabel at index i
      //
      long int getLabel( int i ) const ;
      long int getLabelBySlice( int i ) const ;

      //
      //  get the accumulative cost at index i
      //
      float getAccCost( int i ) const ;

      //
      //  get the cost at index i
      //
      float getCost( int i ) const ;

      //
      //  sliceExits - is slice s in the path?
      //
      bool sliceExists( int s );

      vector< int >& getXs() ;
      vector< int >& getYs() ;

      //
      //  get X for slice i
      //
      int getX( int i ) const;

      //
      //  get Y for slice i
      //
      int getY( int i ) const ;

      //
      //  return the label for index i
      //
      long int getIndex( int i );

      //
      //  getLastLabel
      //
      long int getLastLabel() const;

      //
      //  getFirstLabel
      //
      long int getfirstLabel() const;

      //
      // set the VTK filename
      //
      void setVTKFilename( string vtk_filename );

      //
      // get the vkt filenames (should just be one filename)
      //
      vector< string > getVTKFilenames() ;

      //
      //  id for this path
      //
      unsigned int getID();

      // 
      // set the id for this path
      //
      void setID( unsigned int id );

      //
      //  initialize
      //
      bool init() const ;

      //
      //  size
      //
      unsigned int size() const ;


      //
      // initPath - start a path
      //
      void initPath( int slice, long int label, 
                     float cost, float acc_cost, 
                     int x=0, int y=0 ) ;

      //
      //  add to the path at the beginning of the path
      //
      void add( int slice, long int label, float cost, float acc_cost,
                int x=0, int y=0 ) ;

      //
      //  add to the path at the end of the path
      //
      void addEnd( int slice, long int label, float cost, float acc_cost,
                   int x, int y ) ;
     
      //
      //  returns the label for the i'th slice in this path
      //
      long int get( int i ) ;

      //
      // getMinMaxSlice
      //
      void getMinMaxSlice( int& min, int& max ) const ;

      //
      //  print to stdout
      //
      void print() const ;

      //
      //  write to an xml structure 
      //
      void writeXMLPath( TiXmlElement* pt ) ;

      //
      // read an xml structure
      //
      void readXMLPath( TiXmlElement* pathNode ) ;

      //
      // write to a file (not supported)
      //
      void print(ofstream& out) const;

};

//
//
//  List of Paths
//
//
class ListOfPaths
{
   private:

      vector< Path > p_paths;

   public:

      ListOfPaths() ;

      ListOfPaths( string path_filename ) ;

      ListOfPaths( const ListOfPaths& lop ) ;

      ListOfPaths& operator=( const ListOfPaths& P ) ;

      void remove( int index ) ;

      void deletePaths( vector< int > ids ) ;

      unsigned int size() const ;

      Path get( int i ) const  ; 

      Path& getRef( int i ) ; 

      Path* getPathByIndex( unsigned int i ) ;

      Path* getPathById( unsigned int id ) ;

      void addPath( float c, Path P );

      void addPath( Path P );

      void addPaths( ListOfPaths* P );

      Path getMaxPath();

      void resetIDs( bool resetFileNames = false );

      void readPaths( string filename );
      void print( const char* filename ) ;

      bool readXMLPaths( const char* filename ) ;
      void writeXMLPaths( const char* filename ) ;


};

#endif

